﻿using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Cache;
using DotNetNuke.Tests.Utilities.Mocks;
using MbUnit.Framework;
using Moq;
using System;
using System.Collections.Specialized;
using System.Web;
using ZProjectNamespaceNameZ.ZSafeParentProjectNameZ;
using DotNetNuke.Common;

namespace ZSafeProjectNameZ.Tests
{

    /// <summary>
    /// Summary description for EditZParentProjectNameZPresenterFixture
    /// </summary>
    [TestFixture]
    public class EditZParentProjectNameZPresenterFixture
    {
        #region Object being tested
        private EditZParentProjectNameZPresenter _Presenter;
        #endregion

        #region Setup and Mocked objects
        #region Mocked objects
        private Mock<CachingProvider> _MockCache;
        private Mock<IEditZParentProjectNameZ> _View;
        private Mock<IZParentProjectNameZController> _Controller;
        private ZParentProjectNameZInfo _Data;
        private int _tabId;
        #endregion

        #region Setup for each test
        /// <summary>
        /// Setup performs common Arrange work used by the tests.
        /// </summary>
        [SetUp]
        public void Setup()
        {
            // Arrange...
            //      the module's data
            _Data = new ZParentProjectNameZInfo() { CreatedByUser = 21, ModuleId = 5, ItemId = 300, Content = "Hello DotNetNuke!", CreatedByUserName = "Test User", CreatedDate = DateTime.Now };
            _tabId = 9;
            //      the View
            _View = new Mock<IEditZParentProjectNameZ>();
            _View.SetupAllProperties();
            //      the Controller
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict);
            _Controller.Setup(self => self.GetZParentProjectNameZ(_Data.ModuleId, _Data.ItemId)).Returns(_Data);
            //      the background caching
            _MockCache = MockCachingProvider.CreateMockProvider();
            CreatePresenter();
        }
        #endregion
        #endregion

        #region Helpers
        #region - for Presenter
        public void CreatePresenter(Mock<IEditZParentProjectNameZ> mockedView, Mock<IZParentProjectNameZController> mockedController, Mock<HttpContextBase> mockedHttpContext, ZParentProjectNameZInfo data, int tabId)
        {
            _Presenter = new EditZParentProjectNameZPresenter(mockedView.Object, mockedController.Object)
            {
                HttpContext = mockedHttpContext.Object,
                ModuleId = data.ModuleId,
                UserId = data.CreatedByUser,
                TabId = tabId
            };

        }

        private void CreatePresenter()
        {
            NameValueCollection requestParams = new NameValueCollection();
            requestParams.Add("ItemId", _Data.ItemId.ToString());
            CreatePresenter(_View, _Controller, CreateHttpContext(requestParams), _Data, _tabId);
        }

        public void CreatePresenter(Mock<HttpContextBase> mockedHttpContext)
        {
            CreatePresenter(_View, _Controller, mockedHttpContext, _Data, _tabId);
        }
        #endregion

        #region - for HttpContextBase
        private Mock<HttpContextBase> CreateHttpContext(NameValueCollection requestParams)
        {
            return CreateHttpContext(new Mock<HttpRequestBase>(), new Mock<HttpResponseBase>(), requestParams);
        }

        private Mock<HttpContextBase> CreateHttpContext( Mock<HttpResponseBase> mockedHttpResponse)
        {
            return CreateHttpContext(new Mock<HttpRequestBase>(), mockedHttpResponse, null);
        }

        private Mock<HttpContextBase> CreateHttpContext(Mock<HttpResponseBase> mockedHttpResponse, NameValueCollection requestParams)
        {
            return CreateHttpContext(new Mock<HttpRequestBase>(), mockedHttpResponse, requestParams);
        }

        private Mock<HttpContextBase> CreateHttpContext(Mock<HttpRequestBase> mockedHttpRequest, Mock<HttpResponseBase> mockedHttpResponse, NameValueCollection requestParams)
        {
            mockedHttpRequest.Setup(self => self.Params).Returns(requestParams);
            Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
            mockHttpContext.Setup(self => self.Response).Returns(mockedHttpResponse.Object);
            mockHttpContext.Setup(self => self.Request).Returns(mockedHttpRequest.Object);
            return mockHttpContext;
        }
        #endregion
        #endregion

        #region Test Constructor
        /// <summary>
        /// 
        /// </summary>
        [Test]
        [Description("Ensure that the constructor checks for a non-null Controller object")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_Constructor_Requires_Non_Null_Controller()
        {
            // Arrange (see the SetUp method)
            // Act
            // Assert
            Assert.Throws<ArgumentNullException>(() => { _Presenter = new EditZParentProjectNameZPresenter(_View.Object, null); });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <remarks>
        /// Note that it is impossible for presenters to perform their own validation
        /// of the View before calling the base class constructor; the base constructor
        /// does not perform validation for a null View, but the base's constructor uses
        /// the View to set its Model. Attempting to use a non-null view will result in 
        /// a NullReferenceException.
        /// </remarks>
        [Test]
        [Description("Ensure that the constructor checks for a non-null View object")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_Constructor_Requires_Non_Null_View()
        {
            // Arrange (see the SetUp method)
            // Act
            // Assert
            Assert.Throws<NullReferenceException>(() => { _Presenter = new EditZParentProjectNameZPresenter(null); });
            Assert.Throws<NullReferenceException>(() => { _Presenter = new EditZParentProjectNameZPresenter(null, _Controller.Object); });
        }

        /// <summary>
        /// 
        /// </summary>
        [Test]
        [Description("Ensure that the constructor calls the base class, which sets up the View's Model property")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_Constructor_Sets_View_Model_Instance()
        {
            // Arrange (see the SetUp method)
            // Act
            _Presenter = new EditZParentProjectNameZPresenter(_View.Object, _Controller.Object);

            // Assert
            Assert.IsNotNull(_Presenter.View.Model, "Model was not assigned by the Presenter to the View");
        }
        #endregion

        #region Test Properties
        [Test]
        [Description("When adding a new item, ensure that the Presenter's ItemId is a NullInteger")]
        public void Presenter_Gets_Null_Integer_For_ItemId_When_Adding()
        {
            // Arrange (see the SetUp method)
            CreatePresenter(CreateHttpContext(new NameValueCollection()));

            // Act
            // Assert
            Assert.AreEqual(Null.NullInteger, _Presenter.ItemId);
        }

        [Test]
        [Description("When editing an existing item, ensure that the Presenter retrieves the ItemId from the query string")]
        public void Presenter_Gets_Existing_ItemId_When_Editing()
        {
            // Arrange (see the SetUp method)
            // Act
            // Assert
            Assert.AreEqual(_Data.ItemId, _Presenter.ItemId);
        }
        #endregion

        #region Test OnInit Event Handler
        #region - when Adding new items
        /// <summary>
        /// 
        /// </summary>
        [Test]
        [Description("When adding a new item, ensure that the Presenter creates a default ZParentProjectNameZInfo instance.")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnInit_Sets_Default_Content_When_Adding()
        {
            // Arrange (see the SetUp method)
            CreatePresenter(CreateHttpContext(new NameValueCollection()));

            // Act     -
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert  -
            ZParentProjectNameZInfo ActualInfoInstance = _Presenter.View.Model.Item;
            Assert.IsNotNull(ActualInfoInstance);
            Assert.AreEqual(_Data.ModuleId, ActualInfoInstance.ModuleId);
            Assert.AreEqual(_Data.CreatedByUser, ActualInfoInstance.CreatedByUser);
            Assert.IsNull(ActualInfoInstance.CreatedByUserName);
            Assert.IsNull(ActualInfoInstance.Content);
        }

        /// <summary>
        /// 
        /// </summary>
        [Test]
        [Description("When adding a new item, ensure that the Presenter calls _View.ShowDeleteButton(false) to hide the Delete button.")]
        public void Presenter_OnInit_Hides_Delete_Button()
        {
            // Arrange (see the SetUp method)
            CreatePresenter(CreateHttpContext(new NameValueCollection()));

            // Act
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert
            Assert.AreEqual(Null.NullInteger, _Presenter.ItemId);
            _View.Verify(self => self.ShowDeleteButton(false));
        }

        [Test]
        [Description("When adding a new item, ensure that the Presenter calls _View.ShowAuditControl(false) to hide the AuditControl.")]
        public void Presenter_OnInit_Hides_AuditControl()
        {
            // Arrange (see the SetUp method)
            CreatePresenter(CreateHttpContext(new NameValueCollection()));

            // Act
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert
            Assert.AreEqual(Null.NullInteger, _Presenter.ItemId);
            _View.Verify(self => self.ShowAuditControl(false));
        }


        #endregion

        #region - when Editing existing items
        [Test]
        [Description("When editing an existing item, ensure that the Presenter does not hide the Delete button on the View.")]
        public void Presenter_OnInit_Does_Not_Hide_Delete_Button()
        {
            // Arrange (see the SetUp method)
            // Act
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert
            Assert.AreEqual(_Data.ItemId, _Presenter.ItemId);
            _View.Verify(self => self.ShowDeleteButton(It.IsAny<bool>()), Times.Never());
        }

        [Test]
        [Description("When editing an existing item, ensure that the Presenter does not hide the AuditControl on the View.")]
        public void Presenter_OnInit_Does_Not_Hide_AuditControl()
        {
            // Arrange (see the SetUp method)
            // Act
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert
            Assert.AreEqual(_Data.ItemId, _Presenter.ItemId);
            _View.Verify(self => self.ShowAuditControl(It.IsAny<bool>()), Times.Never());
        }

        [Test]
        [Description("When editing an existing item, ensure that the Presenter assigns to the View the ZParentProjectNameZInfo object retrieved from the collection")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnInit_Gets_Existing_Content_From_Controller_GetZParentProjectNameZs()
        {
            // Arrange (see the SetUp method)
            // Act
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert
            _Controller.VerifyAll();
            ZParentProjectNameZInfo ActualInfoInstance = _Presenter.View.Model.Item;
            Assert.IsNotNull(ActualInfoInstance);
            Assert.AreEqual(_Data.ModuleId, ActualInfoInstance.ModuleId);
            Assert.AreEqual(_Data.CreatedByUser, ActualInfoInstance.CreatedByUser);
            Assert.AreEqual(_Data.CreatedByUserName, ActualInfoInstance.CreatedByUserName);
            Assert.AreEqual(_Data.Content, ActualInfoInstance.Content);
            Assert.AreEqual(_Data.CreatedDate, ActualInfoInstance.CreatedDate);
        } 

        [Test]
        [Description("When editing an existing item, ensure that the Presenter performs a Response.Redirect on an invalid ItemId")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnInit_Redirects_On_Invalid_ItemId_When_Editing()
        {
            // Arrange (see the SetUp method)
            //   + "spoofed" or invalid QueryString parameters
            NameValueCollection queryStringParams = new NameValueCollection();
            queryStringParams.Add("ItemId", "500");
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>();
            //   + Controller expectations
            ZParentProjectNameZInfo noData = null;
            _Controller = new Mock<IZParentProjectNameZController>();
            _Controller.Setup(self => self.GetZParentProjectNameZ(It.IsAny<int>(), It.IsAny<int>())).Returns(noData);
            //   = Create the Presenter that is being tested
            CreatePresenter(CreateHttpContext(mockHttpResponse, queryStringParams));

            // Act
            _View.Raise(self => self.Initialize += null, new System.EventArgs());

            // Assert
            _Controller.VerifyAll();
            mockHttpResponse.Verify(self => self.Redirect(Globals.NavigateURL(_tabId)));
        }
       #endregion
        #endregion

        #region Test Cancel Event Handler
        [Test]
        [Description("When clicking the cancel button, ensure that the Presenter performs a Response.Redirect to the View page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnCancel_Redirects_To_ViewZParentProjectNameZ()
        {
            // Arrange (see the SetUp method)
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>();
            CreatePresenter(CreateHttpContext(mockHttpResponse));

            // Act
            _View.Raise(self => self.Cancel += null, new System.EventArgs());

            // Assert
            mockHttpResponse.Verify(self => self.Redirect(Globals.NavigateURL(_tabId)));
        }
        #endregion

        #region Test Save Event Handler
        #region - when Adding new items
        [Test]
        [Description("When clicking the save button, ensure that the Presenter invokes Add() on the Controller class")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Calls_Controller_Add()
        {
            // Arrange (see the SetUp method)
            //   + QueryString parameters (empty)
            NameValueCollection queryStringParams = new NameValueCollection();
            Mock<HttpContextBase> mockHttpContext = CreateHttpContext(queryStringParams);
            //   + Controller expectations 
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict);
            _Controller.Setup(self => self.AddZParentProjectNameZ(_Data));
            //   = Create the Presenter that is being tested
            CreatePresenter( mockHttpContext);

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(_Data));

            // Assert
            _Controller.VerifyAll();
        }

        [Test]
        [Description("When clicking the save button after Adding, ensure that the Presenter performs a Response.Redirect to the View page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Redirects_To_ViewZParentProjectNameZ_After_Add()
        {
            // Arrange (see the SetUp method)
            //   + QueryString parameters (empty)
            NameValueCollection queryStringParams = new NameValueCollection();
            queryStringParams.Add("ItemId", Null.NullInteger.ToString());
            //   + Response (to test against)
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>(MockBehavior.Strict);
            //   + Controller expectations
            _Controller = new Mock<IZParentProjectNameZController>();
            _Controller.Setup(self => self.AddZParentProjectNameZ(_Data));
            //   = Create the Presenter that is being tested
            CreatePresenter( CreateHttpContext(mockHttpResponse, queryStringParams));

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(_Data));

            // Assert
            mockHttpResponse.Verify(self => self.Redirect(Globals.NavigateURL(_tabId)));
        }

        [Test]
        [Description("When clicking the save button after a failing Add attempt, ensure that the Presenter does not Redirect away from the Edit page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Does_Not_Redirect_When_Add_Fails()
        {
            // Arrange (see the SetUp method)
            //   + QueryString parameters (empty)
            NameValueCollection queryStringParams = new NameValueCollection();
            queryStringParams.Add("ItemId", Null.NullInteger.ToString());
            //   + Response (to test against)
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>(MockBehavior.Strict);
            //   + Controller expectations
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict);
            _Controller.Setup(self => self.AddZParentProjectNameZ(_Data)).Returns(Null.NullInteger);
            //   = Create the Presenter that is being tested
            CreatePresenter( CreateHttpContext(mockHttpResponse, queryStringParams));

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(_Data));

            // Assert
            _Controller.VerifyAll();
            mockHttpResponse.VerifyAll();
        }
        #endregion

        #region - when Editing existing items
        [Test]
        [Description("When clicking the save button, ensure that the Presenter invokes Update() on the Controller class")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Calls_Controller_Update()
        {
            // Arrange (see the SetUp method)
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict);
            _Controller.Setup(self => self.UpdateZParentProjectNameZ(_Data));
            //   = Create the Presenter that is being tested
            CreatePresenter();

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(_Data));

            // Assert
            _Controller.VerifyAll();
        }

        [Test]
        [Description("When clicking the save button after Updating, ensure that the Presenter performs a Response.Redirect to the View page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Redirects_To_ViewZParentProjectNameZ_After_Update()
        {
            // Arrange (see the SetUp method)
            //   + QueryString parameters (empty)
            NameValueCollection queryStringParams = new NameValueCollection();
            queryStringParams.Add("ItemId", _Data.ItemId.ToString());
            //   + Response (to test against)
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>();
            //   + Controller expectations
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict);
            _Controller.Setup(self => self.UpdateZParentProjectNameZ(_Data));
            //   = Create the Presenter that is being tested
            CreatePresenter(CreateHttpContext(mockHttpResponse, queryStringParams));

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(_Data));

            // Assert
            _Controller.VerifyAll();
            mockHttpResponse.Verify(self => self.Redirect(Globals.NavigateURL(_tabId)));
        }
        #endregion

        #region - when given Null ZParentProjectNameZInfo
        [Test]
        [Description("When handling the save event without a ZParentProjectNameZInfo in the UIEventArgs, ensure that the Presenter does not Redirect away from the Edit page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Does_Not_Redirect_Given_Null_Info_In_EventArgs()
        {
            // Arrange (see the SetUp method)
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>(MockBehavior.Strict);
            CreatePresenter(CreateHttpContext(mockHttpResponse));

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(null));

            // Assert
            mockHttpResponse.VerifyAll();
        }

        [Test]
        [Description("When handling the save event without a ZParentProjectNameZInfo in the UIEventArgs, ensure that the Presenter does not call Add() or Update() on the Controller class")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnSave_Does_Not_Attempt_Add_Or_Update_When_Null_Info_In_EventArgs()
        {
            // Arrange (see the SetUp method)
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict);
            CreatePresenter();

            // Act
            _View.Raise(self => self.Save += null, new UIEventArgs<ZParentProjectNameZInfo>(null));

            // Assert
            _Controller.VerifyAll();
        }
        #endregion
        #endregion

        #region Test Delete Event Handler
        [Test]
        [Description("When clicking the delete button, ensure that the Presenter invokes Delete() on the Controller class")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnDelete_Calls_Controller_Delete()
        {
            // Arrange (see the SetUp method)
            // Act
            _View.Raise(self => self.Delete += null, new System.EventArgs());

            // Assert
            _Controller.VerifyAll();
        }

        [Test]
        [Description("When clicking the delete button, ensure that the Presenter performs a Response.Redirect to the View page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnDelete_Redirects_To_ViewZParentProjectNameZ()
        {
            // Arrange (see the SetUp method)
            NameValueCollection queryStringParams = new NameValueCollection();
            queryStringParams.Add("ItemId", _Data.ItemId.ToString());
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>();
            _Controller.Setup(self => self.DeleteZParentProjectNameZ(_Data.ModuleId, _Data.ItemId));
            CreatePresenter(CreateHttpContext(mockHttpResponse, queryStringParams));

            // Act
            _View.Raise(self => self.Delete += null, new System.EventArgs());

            // Assert
            mockHttpResponse.Verify(self => self.Redirect(Globals.NavigateURL(_tabId)));
        }

        [Test]
        [Description("When clicking the delete button with the item not existing in the database, ensure that the Presenter performs a Response.Redirect to the View page")]
        [Annotation(Gallio.Model.AnnotationType.Info, "Owner: Dan Gilleland")]
        public void Presenter_OnDelete_With_NonExisting_Info_Redirects_To_ViewZParentProjectNameZ()
        {
            // Arrange (see the SetUp method)
            //  MockBehaviour.Strict will ensure that the DeleteZParentProjectNameZ() is NOT called, 
            //  since it is not setup as an expectation
            _Controller = new Mock<IZParentProjectNameZController>(MockBehavior.Strict); 
            ZParentProjectNameZInfo nullData = null;
            _Controller.Setup(self => self.GetZParentProjectNameZ(_Data.ModuleId, _Data.ItemId)).Returns(nullData);
            NameValueCollection queryStringParams = new NameValueCollection();
            queryStringParams.Add("ItemId", _Data.ItemId.ToString());
            Mock<HttpResponseBase> mockHttpResponse = new Mock<HttpResponseBase>();
            CreatePresenter(CreateHttpContext(mockHttpResponse, queryStringParams));

            // Act
            _View.Raise(self => self.Delete += null, new System.EventArgs());

            // Assert
            _Controller.VerifyAll();
            mockHttpResponse.Verify(self => self.Redirect(Globals.NavigateURL(_tabId)));
        }
        #endregion
    } // end of class
} // end of namespace